package com.demo.chapter11future.sync2;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;
import com.demo.chapter11future.sync.Shop;

public class Test {
	
	private static List<Shop> shops = Arrays.asList(new Shop("BestPrice"), new Shop("LetsSaveBig"), new Shop("MyFav"), new Shop("BuyAll"));
	//创建一个线程池，线程池中线程数目为100或商店数目两者较小的值
//	private final Executor executor = Executors.newFixedThreadPool(Math.min(shops.size(), 100), new ThreadFactory(){
//		@Override
//		public Thread newThread(Runnable r) {
//			Thread t = new Thread();
//			//使用守护线程，这种方式不会阻止程序的关停
//			t.setDaemon(true);
//			return t;
//		}
//	});
	private final Executor executor = Executors.newFixedThreadPool(Math.min(shops.size(), 100));
	
	//从shops列表里获取product产品的价格
	public List<String> findPrice(String product){
		return shops.stream().map(shop -> String.format("%s price is %s", shop.getName(), shop.getPrice(product)))
			.collect(Collectors.toList());
	}
	
	//从shops列表里获取product产品的价格，parallel
	//parallel依赖于线程数量固定的通用线程池，扩展性不好
	//计算密集型建议使用
	public List<String> findPrice2(String product){
		return shops.stream().parallel().map(shop -> String.format("%s price is %s", shop.getName(), shop.getPrice(product)))
				.collect(Collectors.toList());
	}
	
	//以CompletableFuture的方式
	//IO密集型建议使用
	public List<String> findPrice3(String product){
		List<CompletableFuture<String>> priceFutures = shops
				.stream()
				.map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is " + shop.getPrice(product), executor))
				.collect(Collectors.toList());
		//join和Future的get有相同的含义
		return priceFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
		//如果写两个map在一个流里是起不到效果的，因为第一个shop的第一个map执行完后，会执行第二个map，然后会执行第二个shop的第一个map...，相当于findPrice的时间
	}
	
	
	public static void main(String[] args) {
		Test test = new Test();
		//可用的cpu个数
		System.out.println(Runtime.getRuntime().availableProcessors());
		
		//用同步的方式获取价格，因为只提供了同步api
		long start = System.nanoTime();
		test.findPrice("iphone");
		long incocationTime = ((System.nanoTime() - start) / 1_000_000);
        System.out.println("Invocation returned after " + incocationTime + " msecs");
        
        //用并行流改善后
        long start2 = System.nanoTime();
        test.findPrice2("iphone");
        long incocationTime2 = ((System.nanoTime() - start2) / 1_000_000);
        System.out.println("Invocation returned after " + incocationTime2 + " msecs");
        
        long start3 = System.nanoTime();
        test.findPrice3("iphone");
        long incocationTime3 = ((System.nanoTime() - start3) / 1_000_000);
        System.out.println("Invocation returned after " + incocationTime3 + " msecs");
        
	}

}
